package jp.gnt.swf;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

public class SWFObject {

	private SWFHeader header;
	private byte[] byteContent;

	/**
	 * 
	 * @param pathName
	 * @throws IOException
	 */
	public SWFObject(String pathName) throws IOException {
		// get swf content //
		byte[] buffer = new byte[SWFUtils.BUFFER_SIZE];
		byte[] byteArrays = SWFService.getByteArray(pathName);
		InputStream inputStream = new ByteArrayInputStream(byteArrays);
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();

		// parse swf header //
		this.header = new SWFHeader();
		header.parseHeader(inputStream);

		// Get content file //
		int byteCounter = 0;
		while ((byteCounter = inputStream.read(buffer, 0, SWFUtils.BUFFER_SIZE)) != -1) {
			outStream.write(buffer, 0, byteCounter);
		}

		this.byteContent = outStream.toByteArray();
	}

	/**
	 * Repair variables in swf content file with images parameter
	 */
	public void repairImages(Map<Integer, String> images) {
		byte[] buffer = new byte[SWFUtils.BUFFER_SIZE];
		ByteArrayInputStream ins = new ByteArrayInputStream(this.byteContent);
		ByteArrayOutputStream outs = new ByteArrayOutputStream();

		try {
			// Looping throughout swf content //
			while (ins.read(buffer, 0, 2) != -1) {
				boolean islongTagHeader = false;

				// Get tag code and length of tag //
				int[] tagCodeAndLength = SWFService.getTagCodeAndLength(buffer);
				int tagCode = tagCodeAndLength[0];
				int dataLength = tagCodeAndLength[1];

				// Reload length of tag if is long-tag-header //
				if (dataLength >= 0x3F) {
					islongTagHeader = true;
					ins.read(buffer, 0, 4);
					dataLength = (int) SWFService.convertByte2Long(buffer, 4);
				}

				// Check tag code //
				switch (tagCode) {
				case SWFUtils.TAG_CODE.DEFINE_BITS_LOSSLESS2:
				case SWFUtils.TAG_CODE.DEFINE_BITS_LOSSLESS:
				case SWFUtils.TAG_CODE.DEFINE_BITS_JPEG3:
				case SWFUtils.TAG_CODE.DEFINE_BITS_JPEG2:
					ins.read(buffer, 0, 2);
					int objectId = SWFService.convertByte2Int(buffer, 2);
					dataLength -= 2;

					// Get param image //
					byte[] dataImage = null;

					if (images != null) {
						String imagePath = images.get(objectId);
						if (imagePath != null && imagePath != "") {
							// // Replace tag /
							// if(tagCode ==
							// SWFUtils.TAG_CODE.DEFINE_BITS_JPEG2) {
							// tagCode = 35;
							// }
							// // Replace tag /
							// if (tagCode ==
							// SWFUtils.TAG_CODE.DEFINE_BITS_LOSSLESS
							// || tagCode ==
							// SWFUtils.TAG_CODE.DEFINE_BITS_LOSSLESS2) {
							// tagCode = 35;
							// }
							dataImage = SWFService.getDataImage(imagePath, tagCode);
						}
					}

					if (dataImage != null && dataImage.length > 0) {
						// Write tag code and length, +2 bytes objectId //

						byte[] tgl = SWFService.revertTagCodeAndLength(tagCode, dataImage.length + 2, true);
						outs.write(tgl);

						// Write objectId /
						byte[] ob2 = SWFService.convertInt2Byte(objectId);
						outs.write(ob2, 0, 2);

						outs.write(dataImage);
						// Skip (n) bytes of old image //
						ins.skip(dataLength);
						dataLength = 0;
					} else {
						// Write tag code and length, +2 bytes objectId //
						byte[] tgl = SWFService.revertTagCodeAndLength(tagCode, dataLength + 2, islongTagHeader);
						outs.write(tgl);

						// Write objectId /
						byte[] ob2 = SWFService.convertInt2Byte(objectId);
						outs.write(ob2, 0, 2);
					}
					break;
				default:
					// Write tagcode and length //
					byte[] tcl = SWFService.revertTagCodeAndLength(tagCode, dataLength, islongTagHeader);
					outs.write(tcl);
				}

				// Get all remain content of tag //
				byte[] bytes = SWFService.readBytes(ins, dataLength);
				outs.write(bytes);
			}

			this.byteContent = outs.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Repair variables in swf content file with params parameter
	 */
	public void repairParams(Map<String, String> params) {
		byte[] buffer = new byte[SWFUtils.BUFFER_SIZE];
		ByteArrayInputStream ins = new ByteArrayInputStream(this.byteContent);
		ByteArrayOutputStream outs = new ByteArrayOutputStream();

		try {
			// Looping throughout swf content //
			while (ins.read(buffer, 0, 2) != -1) {
				boolean islongTagHeader = false;

				// Get tag code and length of tag //
				int[] tagCodeAndLength = SWFService.getTagCodeAndLength(buffer);
				int tagCode = tagCodeAndLength[0];
				int dataLength = tagCodeAndLength[1];

				// Reload length of tag if is long-tag-header //
				if (dataLength >= 0x3F) {
					islongTagHeader = true;
					ins.read(buffer, 0, 4);
					dataLength = (int) SWFService.convertByte2Long(buffer, 4);
				}

				// Check tag code //
				switch (tagCode) {
				case SWFUtils.TAG_CODE.DO_ACTION:
					ins.read(buffer, 0, dataLength);
					byte[] actionParams = SWFService.repairActionParams(params, buffer, dataLength);
					byte[] tl = SWFService.revertTagCodeAndLength(tagCode, actionParams.length, true);
					outs.write(tl);
					outs.write(actionParams);
					dataLength = 0;
					break;
				default:
					// Write tagcode and length //
					byte[] tcl = SWFService.revertTagCodeAndLength(tagCode, dataLength, islongTagHeader);
					outs.write(tcl);
				}

				// Get all remain content of tag //
				byte[] bytes = SWFService.readBytes(ins, dataLength);
				outs.write(bytes);
			}

			this.byteContent = outs.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @return
	 */
	public byte[] toByteArrays() {
		ByteArrayOutputStream outs = new ByteArrayOutputStream();

		try {
			// Update file length /
			this.header.updateFileLength(this.byteContent.length);

			// Export all data to output //
			outs.write(this.header.toByteArray());
			outs.write(this.byteContent);
		} catch (IOException e) {
			e.printStackTrace();
		}

		return outs.toByteArray();
	}

	/**
	 * 
	 * @return
	 */
	public ByteArrayInputStream getInputStream() {
		return new ByteArrayInputStream(this.toByteArrays());
	}

	/**
	 * 
	 * @return
	 */
	public SWFHeader getHeader() {
		return header;
	}

	/**
	 * 
	 * @param header
	 */
	public void setHeader(SWFHeader header) {
		this.header = header;
	}

	/**
	 * 
	 * @return
	 */
	public byte[] getByteContent() {
		return byteContent;
	}

	/**
	 * 
	 * @param byteContent
	 */
	public void setByteContent(byte[] byteContent) {
		this.byteContent = byteContent;
	}
}
